home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / terms / tipx / xfer / tipsz.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-11  |  40.0 KB  |  1,837 lines

  1. char *numeric_revision = "tipsz 1.01";
  2. #define BUFFERED_WRITE
  3. /*+-------------------------------------------------------------------------
  4.     tipsz.c - X/Y/ZMODEM send program
  5.   Derived from public domain source by Chuck Forsberg, Omen Technologies
  6.   wht%n4hgf@emory.mathcs.emory.edu
  7.  
  8.     Usage:    tipsz [-X -Y -Z] [-12+abdefkLlNnquvwy] [-] file ...
  9.         (Y) = Option applies to YMODEM only
  10.         (Z) = Option applies to ZMODEM only
  11.         a (ASCII) change NL to CR/LF
  12.         b Binary file transfer override
  13.         f send Full pathname (Y/Z)
  14.         k Send 1024 byte packets (Y)
  15.         L N Limit subpacket length to N bytes (Z)
  16.         l N Limit frame length to N bytes (l>=L) (Z)
  17.         n send file if source newer (Z)
  18.         N send file if source newer or longer (Z)
  19.         o Use 16 bit CRC instead of 32 bit CRC (Z)
  20.         p Protect existing destination file (Z)
  21.         r Resume/Recover interrupted file transfer (Z)
  22.         q Quiet (no progress reports)
  23.         u Unlink file after transmission
  24.         w N Window is N bytes (Z)
  25.         y Yes,overwrite existing file (Z)
  26.         @file reads a list of filenames from 'file'
  27.  
  28.   Defined functions:
  29.     SIGALRM_handler()
  30.     bye_bye(sig)
  31.     cancel_transaction(sig)
  32.     determine_transaction_time()
  33.     flushline()
  34.     get_file_list_name(namep)
  35.     getinsync(flag)
  36.     getnak()
  37.     getzrxinit()
  38.     log_packet_buffer(buf,len)
  39.     main(argc,argv)
  40.     onintr()
  41.     purgeline()
  42.     readline(n)
  43.     readock(timeout,count)
  44.     report_rcvr_cancelled(place_happened)
  45.     report_rcvr_skipped()
  46.     report_send_stats(filepos)
  47.     report_send_transaction()
  48.     rewind_file_list()
  49.     saybibi()
  50.     send_cancel()
  51.     sendline(ch)
  52.     sendzsinit()
  53.     set_file_list(pathc,pathv)
  54.     substr(s,t)
  55.     usage()
  56.     wcputsec(buf,sectnum,cseclen)
  57.     wcs(oname)
  58.     wcsend()
  59.     wctx(flen)
  60.     wctxpn(name)
  61.     xbuf_build(buf,count)
  62.     xsendline(ch)
  63.     zbuf_build(buf,count)
  64.     zsendfdata()
  65.     zsendfile(buf,blen)
  66.  
  67. --------------------------------------------------------------------------*/
  68. /*+:EDITS:*/
  69. /*:08-23-1990-13:48-wht@tridom-add mode 4 code */
  70. /*:05-21-1990-16:00-wht@tridom-adapt ecu xfer protocols for tipwht */
  71.  
  72. /*
  73.   Error return conditions
  74.     255:     usage
  75.     254:     protocol failed (bad line conditions,brain dead remote)
  76.     253:     could not open any files
  77.     128-192: process terminated with signal==code-128 (64 signals allowed for)
  78.              signal 0 == program logic error (see cancel_transaction)
  79.     127:     127 or more files not transmitted (see ~/.tip/log)
  80.     1-126:   count of files not transmitted (see ~/.tip/log)
  81.     0:       file transfer completely successful
  82. */
  83.  
  84. char *substr(),*getenv();
  85.  
  86. #include <stdio.h>
  87. #include <signal.h>
  88. #include <setjmp.h>
  89. #include <ctype.h>
  90. #include <fcntl.h>
  91. #include "zmodem.h"
  92. #include "zlint.h"
  93.  
  94. extern char *sys_errlist[];
  95. extern unsigned short crctab[];    /* wht */
  96. extern unsigned long total_data_chars_xfered; /* zcurses.c */
  97. extern int errno;
  98. extern int show_window;
  99. extern int Rxtimeout;    /* Tenths of seconds to wait for something */
  100. extern char Rxhdr[4];    /* Received header */
  101. extern char Txhdr[4];    /* Transmitted header */
  102. extern int Txfcs32;        /* TURE means send binary frames with 32 bit FCS */
  103. extern long Rxpos;    /* Received file position */
  104. extern long Txpos;    /* Transmitted file position */
  105. extern char *frametypes[];
  106. extern char Attn[];        /* Attention string rx sends to tx on err */
  107. extern char s256[];
  108.  
  109. #define RETRYMAX 10        /* non-zmodem retry count on block send */
  110. #define VMIN_COUNT 2    /* must not exceed 255 */
  111. unsigned char vmin_count = VMIN_COUNT;
  112. int iofd = 0;        /* line io fd */
  113. #ifdef BUFFERED_WRITE
  114. FILE *iofp;
  115. char iofpbuf[256];
  116. #endif
  117.  
  118.  
  119. /*
  120.  * Attention string to be extipted by receiver to interrupt streaming data
  121.  *  when an error is detected.  A pause (0336) may be needed before the
  122.  *  ^C (03) or after it.
  123.  */
  124. #if defined(READCHECK)
  125. char Myattn[] = { 0 };
  126. #else
  127. #if defined(M_SYS5)
  128. char Myattn[] = { 03,0336,0 };
  129. #else
  130. char Myattn[] = { 0 };
  131. #endif
  132. #endif
  133.  
  134. FILE *in;
  135.  
  136. char *Cmdstr;        /* Pointer to the command string */
  137. char *bottom_label = (char *)0;
  138. char Crcflg;
  139. char Lastrx;
  140. char Lzconv;        /* Local ZMODEM file conversion request */
  141. char Lzmanag;        /* Local ZMODEM file management request */
  142. char Lztrans;
  143. char Pathname[PATHLEN];
  144. char curr_dir[256];
  145. char s128[128];
  146. char txbuf[1024];
  147. char zconv;                /* ZMODEM file conversion request */
  148. char zmanag;            /* ZMODEM file management request */
  149. char ztrans;            /* ZMODEM file transport request */
  150. int Ascii=0;            /* Add CR's for brain damaged programs */
  151. int Cmdack1;            /* Rx ACKs command,then do it */
  152. int Cmdtries = 11;
  153. int Command = 0;        /* Send a command,then exit. */
  154. int Dontread;            /* Don't read the buffer,it's still there */
  155. int Dottoslash=0;        /* Change foo.bar.baz to foo/bar/baz */
  156. int Exitcode = 0;
  157. int Filcnt=0;            /* count of number of files opened */
  158. int FilesTotal;
  159. int Filesleft;
  160. int Fullname=0;            /* transmit full pathname */
  161. int Lastn;                /* Count of last buffer read or -1 */
  162. int Lfseen=0;
  163. int Noeofseen;
  164. int Nozmodem = 0;
  165. int Optiong;            /* no wait for block ACK's */
  166. int Quiet=0;            /* overrides logic that would otherwise set verbose */
  167. int Rxflags = 0;
  168. int SameZrposAgain=0;    /* How many times we've been ZRPOS'd same place (wht) */
  169. int Tframlen = 0;        /* Override for tx frame length */
  170. int Totsecs;            /* total number of blocks this file */
  171. int Twostop = 0;        /* use two stop bits */
  172. int Unlinkafter=0;        /* Unlink file after it is sent */
  173. int Wantfcs32 = TRUE;    /* want to send 32 bit FCS */
  174. int Xmodem=0;            /* XMODEM Protocol - don't send pathnames */
  175. int Zctlesc;            /* Encode control characters */
  176. int Zmodem=0;            /* ZMODEM protocol requested by receiver */
  177. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  178. int blklen=128;            /* length of transmitted records */
  179. int blklen_original;
  180. int blkopt=0;            /* Override value for zmodem blklen */
  181. int tipsz_flag = 1;
  182. int skip_count = 0;        /* skipped files */
  183. int errors;
  184. int firstsec;
  185. int log_packets = 0;
  186. int no_files = 0;
  187. int npats = 0;
  188. long Lastread;        /* Beginning offset of last buffer read */
  189. long Lastsync;        /* Last offset to which we got a ZRPOS */
  190. long Lrxpos;            /* Receiver's last reported offset */
  191. long TotalLeft;
  192. long TotalToSend;
  193. long bytcnt;
  194. long rx_char_count = 0L;
  195. long this_file_length;
  196. long tx_char_count = 0L;
  197. unsigned Baudrate;
  198. unsigned Rxbuflen = 16384;    /* Receiver's max buffer length */
  199. unsigned Txwcnt;        /* Counter used to space ack requests */
  200. unsigned Txwindow;        /* Control the size of the transmitted window */
  201. unsigned Txwspac;        /* Spacing between zcrcq requests */
  202. unsigned int bad_condx_blklen = 0;    /* if <>0,blklen has been reduced (wht) */
  203. unsigned int bad_condx_frame_count = 0;    /* frame # last SameZrposAgain (wht) */
  204. unsigned int this_file_frame_count;    /* count of frames sent this file (wht) */
  205.  
  206. #define MAX_PATHS 512
  207. char *paths[MAX_PATHS];
  208.  
  209. jmp_buf tohere;        /* For the interrupt on RX timeout */
  210. jmp_buf intrjmp;    /* For the interrupt on RX CAN */
  211.  
  212. int file_list_pathc;
  213. int file_list_path_current;
  214. char **file_list_pathv;
  215. int required_type = 0;
  216. FILE *fpflst = (FILE *)0;
  217.  
  218. /*+-------------------------------------------------------------------------
  219.     log_packet_buffer(buf,len)
  220. --------------------------------------------------------------------------*/
  221. void
  222. log_packet_buffer(buf,len)
  223. register unsigned char *buf;
  224. register int len;
  225. {
  226. char xbuf[32];
  227.  
  228.     while(len--)
  229.     {
  230.         sprintf(xbuf,"%02x ",*buf++);
  231.         write(log_packets,xbuf,strlen(xbuf));
  232.     }
  233.     write(log_packets,"\n",1);
  234.  
  235. }    /* end of log_packet_buffer */
  236.  
  237. /*+-------------------------------------------------------------------------
  238.     rewind_file_list()
  239. --------------------------------------------------------------------------*/
  240. void
  241. rewind_file_list()
  242. {
  243.     file_list_path_current = 0;
  244.     if(fpflst)
  245.     {
  246.         fclose(fpflst);
  247.         fpflst = (FILE *)0;
  248.     }
  249. }    /* end of rewind_file_list */
  250.  
  251. /*+-------------------------------------------------------------------------
  252.     set_file_list(pathc,pathv)
  253. --------------------------------------------------------------------------*/
  254. void
  255. set_file_list(pathc,pathv)
  256. int pathc;
  257. char **pathv;
  258. {
  259.  
  260.     file_list_pathc = pathc;
  261.     file_list_pathv = pathv;
  262.     rewind_file_list();
  263. }    /* end of set_file_list */
  264.  
  265. /*+-------------------------------------------------------------------------
  266.     get_file_list_name(namep)
  267. --------------------------------------------------------------------------*/
  268. get_file_list_name(namep)
  269. char **namep;
  270. {
  271. register char *cptr;
  272. static char name[256];
  273.  
  274. try_fpflst:
  275.     if(fpflst)
  276.     {
  277.         if(fgets(name,sizeof(name),fpflst) != NULL)
  278.         {
  279.             name[strlen(name) - 1] = 0;
  280.             *namep = name;
  281.             return(1);
  282.         }
  283.         fclose(fpflst);
  284.         fpflst = (FILE *)0;
  285.     }
  286.  
  287. next_arg:
  288.     if(file_list_path_current == file_list_pathc)
  289.         return(0);
  290.     cptr = file_list_pathv[file_list_path_current++];
  291.     if(*cptr != '@')
  292.     {
  293.         *namep = cptr;
  294.         return(1);
  295.     }
  296.     cptr++;
  297.     if((fpflst = fopen(cptr,"r")) == NULL)
  298.         goto next_arg;
  299.     goto try_fpflst;
  300.  
  301. }    /* end of get_file_list_name */
  302.  
  303. /*+-------------------------------------------------------------------------
  304.     bye_bye(sig)
  305. --------------------------------------------------------------------------*/
  306. void
  307. bye_bye(sig)
  308. int sig;
  309. {
  310.     exit(sig+128);
  311. }    /* end of bye_bye */
  312.  
  313. /*+-------------------------------------------------------------------------
  314.     cancel_transaction(sig)
  315. called by signal interrupt or terminate to clean things up
  316. --------------------------------------------------------------------------*/
  317. void
  318. cancel_transaction(sig)
  319. {
  320.     if(Zmodem)
  321.         zmputs(Attn);
  322.     send_cancel();
  323.     mode(0);
  324.     if(sig >= 0)
  325.     {
  326.         sprintf(s128,"tipsz aborted (signal %d)",sig);
  327.         report_str(s128,0);
  328.     }
  329.     report_tx_ind(0);
  330.     report_rx_ind(0);
  331.     report_uninit(0);
  332.     bye_bye(sig);
  333. }    /* end of cancel_transaction */
  334.  
  335. /* Called when ZMODEM gets an interrupt (^X) */
  336. onintr()
  337. {
  338.     signal(SIGINT,SIG_IGN);
  339. #if defined(M_SYS5)
  340.     report_rx_ind(0);
  341.     report_tx_ind(0);
  342. #endif
  343.     longjmp(intrjmp,-1);
  344. }
  345.  
  346.  
  347. /*+-------------------------------------------------------------------------
  348.     report_send_transaction()
  349. --------------------------------------------------------------------------*/
  350. void
  351. report_send_transaction()
  352. {
  353.     if(Xmodem)
  354.     {
  355.         long blocks = (TotalToSend >> 7) + ((TotalToSend % 128) != 0);
  356.         long secs = 7        /* slightly worse than average first nak delay */
  357.             + (blocks / 5L)                /* assume .2 sec ack time */
  358.             + ((blocks * (128L + 16L)) / (Baudrate / 10));
  359.         if(!secs)
  360.             secs = 10L;
  361.         sprintf(s128,"Sending %ld blocks time ~= %ld:%02ld",
  362.             blocks,secs/60,secs % 60);
  363.     }
  364.     else
  365.     {
  366.         long min_100 =
  367.             (FilesTotal * 2L) + (((TotalToSend * 11L)) * 10L) / (Baudrate * 6L);
  368.         if(!min_100)
  369.             min_100 = 4L;
  370. #if defined(M_I286)    /* slower */
  371.         else if(Baudrate > 4800)
  372.         {
  373.             min_100 *= 13;
  374.             min_100 /= 9;    /* yech ... empirical */
  375.         }
  376. #endif
  377.         sprintf(s128,"Sending %ld bytes  total time ~= %2lu:%02lu",
  378.             TotalToSend,min_100 / 100,((min_100 % 100) * 60L) / 100L);
  379.     }
  380.     report_transaction(s128);
  381.  
  382. }    /* end of report_send_transaction */
  383.  
  384. /*+-------------------------------------------------------------------------
  385.     report_send_stats(filepos)
  386. --------------------------------------------------------------------------*/
  387. void
  388. report_send_stats(filepos)
  389. long filepos;
  390. {
  391.  
  392.     if(Xmodem)
  393.         sprintf(s128,"File %d%% complete",
  394.             (this_file_length == 0) ? (int)100 :
  395.             (int)((filepos * 100L) / this_file_length));
  396.     else
  397.         sprintf(s128,"This file %d%%, transaction %d%% complete",
  398.             (this_file_length == 0) ? (int)100 :
  399.                     (int)((filepos * 100L)/this_file_length),
  400.             (TotalToSend == 0) ? (int)100 :
  401.                     (int)(((total_data_chars_xfered + filepos) * 100L)
  402.                         / TotalToSend));
  403.     report_str(s128,0);
  404.     report_txpos(filepos);
  405.  
  406. }    /* end of report_send_stats */
  407.  
  408. /*+-------------------------------------------------------------------------
  409.     report_rcvr_cancelled(place_happened)
  410. --------------------------------------------------------------------------*/
  411. void
  412. report_rcvr_cancelled(place_happened)
  413. char *place_happened;
  414. {
  415.     strcpy(s128,"SEND CANCELLED");
  416.     report_str(s128 + 5,1);
  417.     skip_count++;
  418.     report_error_count();
  419. }    /* end of report_rcvr_cancelled */
  420.  
  421. /*+-------------------------------------------------------------------------
  422.     report_rcvr_skipped()
  423. --------------------------------------------------------------------------*/
  424. void
  425. report_rcvr_skipped()
  426. {
  427.     sprintf(s128,"SEND skipped: %s",Pathname);
  428.     report_str(s128 + 5,-1);
  429.     skip_count++;
  430.     report_error_count();
  431.     TotalToSend -= this_file_length;
  432.     report_send_transaction();
  433. }    /* end of report_rcvr_skipped */
  434.  
  435.  
  436. /*+-------------------------------------------------------------------------
  437.     xsendline(ch)
  438. --------------------------------------------------------------------------*/
  439. xsendline(ch)
  440. char ch;
  441. {
  442. #ifdef BUFFERED_WRITE
  443.     fputc(ch,iofp);
  444. #else
  445.     write(iofd,&ch,1);
  446. #endif
  447.     ++tx_char_count;
  448. }    /* end of xsendline */
  449.  
  450. /*+-------------------------------------------------------------------------
  451.     sendline(ch)
  452. --------------------------------------------------------------------------*/
  453. sendline(ch)
  454. char ch;
  455. {
  456.     xsendline(ch);
  457. }    /* end of sendline */
  458.  
  459. flushline()
  460. {
  461. #ifdef BUFFERED_WRITE
  462.     fflush(iofp);
  463. #endif
  464. }
  465.  
  466. main(argc,argv)
  467. char *argv[];
  468. {
  469. register char *cp;
  470. long min_100;
  471. char **patts = paths;
  472. char **gargv = argv;
  473. int gargc = argc;
  474.  
  475.     signal(SIGINT,bye_bye);
  476.     signal(SIGTERM,bye_bye);
  477.  
  478.     get_curr_dir(curr_dir,sizeof(curr_dir));
  479.  
  480.     Rxtimeout = 600;
  481.     npats=0;
  482.     if(argc<2)
  483.         usage();
  484.     while(--argc)
  485.     {
  486.         cp = *++argv;
  487.         if(*cp == '-')
  488.         {
  489.             cp++;
  490.             switch(*cp++)
  491.             {
  492.             case 'X':
  493.                 required_type = 1;
  494.                 Xmodem = TRUE;
  495.                 break;
  496.             case 'Y':
  497.                 required_type = 1;
  498.                 Nozmodem = TRUE;
  499.                 blklen=1024;
  500.                 break;
  501.             case 'Z':
  502.                 show_window = 1;
  503.                 required_type = 1;
  504.                 break;
  505.  
  506.             case '+':
  507.                 Lzmanag = ZMAPND;
  508.                 break;
  509.             case 'a':
  510.                 Lzconv = ZCNL;
  511.                 Ascii = TRUE;
  512.                 break;
  513.             case 'b':
  514.                 Lzconv = ZCBIN;
  515.                 break;
  516.             case 'd':
  517.                 ++Dottoslash;
  518.                 /* **** FALL THROUGH TO **** */
  519.             case 'f':
  520.                 Fullname=TRUE;
  521.                 break;
  522.             case ',':
  523.                 log_packets = 1;
  524.                 break;
  525.             case '/':
  526.                 if(--argc < 1)
  527.                     usage();
  528.                 strcpy(curr_dir,*++argv);
  529.                 break;
  530.             case '.':
  531.                 if(--argc < 1)
  532.                     usage();
  533.                 iofd = atoi(*++argv);
  534.                 break;
  535.             case 'C':
  536.                 if(--argc < 1)
  537.                     usage("no label after -C");
  538.                 bottom_label = *++argv;
  539.                 break;
  540.             case 'e':
  541.                 Zctlesc = 1;
  542.                 break;
  543.             case 'k':
  544.                 blklen=1024;
  545.                 break;
  546.             case 'L':
  547.                 if(--argc < 1)
  548.                 {
  549.                     usage();
  550.                 }
  551.                 blkopt = atoi(*++argv);
  552.                 if(blkopt<24 || blkopt>1024)
  553.                         usage();
  554.                 break;
  555.             case 'l':
  556.                 if(--argc < 1)
  557.                 {
  558.                     usage();
  559.                 }
  560.                 Tframlen = atoi(*++argv);
  561.                 if(Tframlen<32 || Tframlen>1024)
  562.                     usage();
  563.                 break;
  564.             case 'N':
  565.                 Lzmanag = ZMNEWL;
  566.                 break;
  567.             case 'n':
  568.                 Lzmanag = ZMNEW;
  569.                 break;
  570.             case 'o':
  571.                 Wantfcs32 = FALSE;
  572.                 break;
  573.             case 'p':
  574.                     Lzmanag = ZMPROT;
  575.                     break;
  576.             case 'r':
  577.                 Lzconv = ZCRESUM;
  578.             case 't':
  579.                 if(--argc < 1)
  580.                 {
  581.                     usage();
  582.                 }
  583.                 Rxtimeout = atoi(*++argv);
  584.                 if(Rxtimeout<10 || Rxtimeout>1000)
  585.                     usage();
  586.                 break;
  587.             case 'u':
  588.                 ++Unlinkafter;
  589.                 break;
  590.             case 'w':
  591.                 if(--argc < 1)
  592.                 {
  593.                     usage();
  594.                 }
  595.                 Txwindow = atoi(*++argv);
  596.                 if(Txwindow < 256)
  597.                     Txwindow = 256;
  598.                 Txwindow = (Txwindow/64) * 64;
  599.                 Txwspac = Txwindow/4;
  600.                 if(blkopt > Txwspac || (!blkopt && Txwspac < 1024))
  601.                     blkopt = Txwspac;
  602.                 break;
  603.             case 'y':
  604.                 Lzmanag = ZMCLOB;
  605.                 break;
  606.             default:
  607.                 usage();
  608.             }
  609.         }
  610.         else if(argc > 0)
  611.         {
  612.             if(npats < MAX_PATHS)
  613.             {
  614.                 npats++;
  615.                 *patts++ = cp;
  616.             }
  617.             else
  618.             {
  619.                 printf("too many filenames to send\n");
  620.                 exit(255);
  621.             }
  622.         }
  623.     }
  624.     if(!required_type || !iofd)
  625.     {
  626.         printf("can only be run by tip\n");
  627.         exit(255);
  628.     }
  629.  
  630.     if(npats < 1 && !Command)
  631.         usage();
  632.  
  633.     set_file_list(npats,paths);
  634.     sprintf(s128,"%s",numeric_revision);
  635.  
  636.     if(log_packets)
  637.     {
  638.     char log_packets_name[64];
  639.     FILE *ftmp;
  640.     int iargv;
  641.         sprintf(log_packets_name,"/tmp/sz%05d.plog",getpid());
  642.         unlink(log_packets_name);
  643.         ftmp = fopen(log_packets_name,"w");
  644.         fclose(ftmp);
  645.         log_packets = open(log_packets_name,O_WRONLY,0644);
  646.         if(log_packets < 0)
  647.             log_packets = 0;
  648.         else
  649.         {
  650.             write(log_packets,"exec: ",6);
  651.             for(iargv = 0; iargv < gargc; iargv++)
  652.             {
  653.                 write(log_packets,gargv[iargv],strlen(gargv[iargv]));
  654.                 write(log_packets," ",1);
  655.             }
  656.             write(log_packets,"\n",1);
  657.         }
  658.     }
  659.  
  660.     report_init(s128);
  661.     mode(1);
  662.  
  663.     if(signal(SIGINT,cancel_transaction) == SIG_IGN)
  664.         signal(SIGINT,SIG_IGN);
  665.     else
  666.         signal(SIGINT,cancel_transaction);
  667.     signal(SIGTERM,cancel_transaction);
  668.  
  669.     report_str("calculating transaction time",-1);
  670.     determine_transaction_time();
  671. #ifdef BUFFERED_WRITE
  672.     iofp = fdopen(iofd,"w");
  673.     setbuffer(iofp,iofpbuf,sizeof(iofpbuf));
  674. #endif
  675.     if(!Xmodem)
  676.     {
  677.         TotalToSend = TotalLeft;
  678.         report_send_transaction();
  679.         report_str("starting remote receiver",-1);
  680.         report_last_txhdr("begin transfer",0);
  681.         if(!Nozmodem)
  682.             write(iofd,"rz\r",3);
  683.         else    /* wht -- why not? */
  684.             write(iofd,"rb\r",3);        /* wht */
  685.         mode(4);
  686.         sleep(2);
  687.         report_str("",-1);
  688.         if(!Nozmodem)
  689.         {
  690.             stohdr(0L);
  691.             zshhdr(ZRQINIT,Txhdr);
  692.         }
  693.     }
  694.     else
  695.         report_last_txhdr("begin transfer",0);
  696.  
  697.     if(wcsend()==ERROR)
  698.     {
  699.         Exitcode=254;        /*wht was 0200 */
  700.         send_cancel();
  701.     }
  702.     mode(0);
  703.     report_uninit(0);
  704.     if(no_files)
  705.         Exitcode = 253;
  706.     exit(Exitcode ? Exitcode : (skip_count > 127) ? 127 : skip_count);
  707.     /*NOTREACHED*/
  708. }
  709.  
  710. /*+-------------------------------------------------------------------------
  711.     wcsend(argc,argp) -- send group of files
  712. --------------------------------------------------------------------------*/
  713. wcsend()
  714. {
  715.     register n;
  716.     char *name;
  717.  
  718.     Crcflg=FALSE;
  719.     firstsec=TRUE;
  720.     bytcnt = -1;
  721.     rewind_file_list();
  722.     while(get_file_list_name(&name))
  723.     {
  724.         Totsecs = 0;
  725.         if(wcs(name)==ERROR)
  726.             return(ERROR);
  727.     }
  728.     Totsecs = 0;
  729.     if(Filcnt==0)
  730.     {    /* bitch if we couldn't open ANY files */
  731.         send_cancel();
  732.         strcpy(s128,"SEND cannot open any requested files");
  733.         report_str(s128 + 5,1);
  734.         sleep(2);        /* allow time for other rz to get ready */
  735.         no_files = 1;
  736.         return(ERROR);    /* ... then cancel */
  737.     }
  738.     if(Zmodem)
  739.         saybibi();
  740.     else if(!Xmodem)
  741.         wctxpn("");
  742.     return(OK);
  743. }
  744.  
  745. /*+-------------------------------------------------------------------------
  746.     wcs(oname) -- send a file
  747. --------------------------------------------------------------------------*/
  748. wcs(oname)
  749. char *oname;
  750. {
  751. register c;
  752. register char *p;
  753. struct stat f;
  754.  
  755.     strcpy(Pathname,oname);    /* global copy of name */
  756.  
  757.     if((in=fopen(oname,"r"))==NULL)
  758.     {
  759.         sprintf(s128,"SEND %s: %s",sys_errlist[errno],oname);
  760.         report_str(s128 + 5,1);
  761.         skip_count++;
  762.         report_error_count();
  763.         return(OK);    /* pass over it,there may be others */
  764.     }
  765.     ++Noeofseen;
  766.     Lastread = 0;
  767.     Lastn = -1;
  768.     Dontread = FALSE;
  769.     /* Check for directory or block special files */
  770.     fstat(fileno(in),&f);
  771.     c = f.st_mode & S_IFMT;
  772.     if(c == S_IFDIR || c == S_IFBLK)
  773.     {
  774.         sprintf(s128,"SEND %s: %s",
  775.             (c == S_IFDIR) ? "directory" : "block device",oname);
  776.         report_str(s128 + 5,1);
  777.         skip_count++;
  778.         report_error_count();
  779.         fclose(in);
  780.         return(OK);
  781.     }
  782.     f.st_mode &= ~(S_ISUID | S_ISGID);
  783.     Filcnt++;
  784.     report_file_send_open(oname,&f);
  785.     this_file_length = f.st_size;
  786.     report_send_stats(0L);
  787.     switch(wctxpn(Pathname))
  788.     {
  789.     case ERROR:
  790.         sprintf(s128,"SEND protocol failure: %s",oname);
  791.         report_str(s128 + 5,1);
  792.         skip_count++;
  793.         report_error_count();
  794.         report_file_close();
  795.         fclose(in);
  796.         return(ERROR);
  797.     case ZSKIP:
  798.         report_rcvr_skipped();
  799.         return(OK);
  800.     }
  801.     if(!Zmodem && wctx(f.st_size)==ERROR)
  802.         return(ERROR);
  803.     if(Unlinkafter)
  804.         unlink(oname);
  805.     return(0);
  806. }
  807.  
  808. /*
  809.  * generate and transmit pathname block consisting of
  810.  *  pathname (null terminated),
  811.  *  file length,mode time and file mode in octal
  812.  *  as provided by the Unix fstat call.
  813.  *  N.B.: modifies the passed name,may extend it!
  814.  */
  815. wctxpn(name)
  816. char *name;
  817. {
  818.     register char *p,*q;
  819.     char name2[PATHLEN];
  820.     struct stat f;
  821.  
  822.     if(Xmodem)
  823.     {
  824.         if((in!=stdin) && *name && fstat(fileno(in),&f)!= -1)
  825.         {
  826.             TotalToSend = f.st_size;
  827.             report_protocol_type("XMODEM");
  828.             report_send_transaction();
  829.             report_xfer_mode((Ascii) ? "ASCII" : "BINARY");
  830.             report_last_txhdr("Waiting on NAK",0);
  831.         }
  832.         return(OK);
  833.     }
  834.     if(!Zmodem)
  835.     {
  836.         report_last_txhdr("START PENDING",0);
  837.         if(getnak())
  838.         {
  839.             report_str("Timeout on pathname nak",1);
  840.             return(ERROR);
  841.         }
  842.     }
  843.  
  844.     q = (char *) 0;
  845.     if(Dottoslash)
  846.     {        /* change . to . */
  847.         for(p=name; *p; ++p)
  848.         {
  849.             if(*p == '/')
  850.                 q = p;
  851.             else if(*p == '.')
  852.                 *(q=p) = '/';
  853.         }
  854.         if(q && strlen(++q) > 8)
  855.         {    /* If name>8 chars */
  856.             q += 8;            /*   make it .ext */
  857.             strcpy(name2,q);    /* save excess of name */
  858.             *q = '.';
  859.             strcpy(++q,name2);    /* add it back */
  860.         }
  861.     }
  862.  
  863.     for(p=name,q=txbuf ; *p; )
  864.         if((*q++ = *p++) == '/' && !Fullname)
  865.             q = txbuf;
  866.     *q++ = 0;
  867.     p=q;
  868.     while(q < (txbuf + 1024))
  869.         *q++ = 0;
  870.     if(!Ascii && (in != stdin) && *name && !fstat(fileno(in),&f))
  871.         sprintf(p,"%lu %lo %o 0 %d %ld",f.st_size,f.st_mtime,
  872.             f.st_mode &= ~(S_ISUID | S_ISGID),
  873.             Filesleft,TotalLeft);
  874.     report_xfer_mode((Lzconv == ZCNL) ? "ASCII" : "BINARY");
  875.     TotalLeft -= f.st_size;
  876.     if(--Filesleft <= 0)
  877.         TotalLeft = 0;
  878.     if(TotalLeft < 0)
  879.         TotalLeft = 0;
  880.  
  881.     /* force 1k blocks if name won't fit in 128 byte block */
  882.     if(txbuf[125])
  883.         blklen=1024;
  884.     else
  885.     {        /* A little goodie for IMP/KMD */
  886.         txbuf[127] = (f.st_size + 127) >>7;
  887.         txbuf[126] = (f.st_size + 127) >>15;
  888.     }
  889.     if(Zmodem)
  890.         return(zsendfile(txbuf,1+strlen(p)+(p-txbuf)));
  891.     report_protocol_type("YMODEM");
  892.     if(wcputsec(txbuf,0,128)==ERROR)
  893.         return(ERROR);
  894.     return(OK);
  895. }
  896.  
  897. getnak()
  898. {
  899.     register firstch;
  900.  
  901.     Lastrx = 0;
  902.     for(;;)
  903.     {
  904.         switch(firstch = readock(50,1))        /* 50 was 800 (80 secs!!) wht */
  905.         {
  906.         case ZPAD:
  907.             if(getzrxinit())
  908.                 return(ERROR);
  909.             Ascii = 0;    /* Receiver does the conversion */
  910.             return(FALSE);
  911.         case TIMEOUT:
  912.             report_str("Timeout",1);
  913.             return(TRUE);
  914.         case WANTG:
  915. #if defined(MODE2OK)
  916.             mode(2);    /* Set cbreak,XON/XOFF,etc. */
  917. #endif
  918.             Optiong = TRUE;
  919.             blklen=1024;
  920.         case WANTCRC:
  921.             Crcflg = TRUE;
  922.         case NAK:
  923.             return(FALSE);
  924.         case CAN:
  925.             if((firstch = readock(20,1)) == CAN && Lastrx == CAN)
  926.                 return(TRUE);
  927.         default:
  928.             break;
  929.         }
  930.         Lastrx = firstch;
  931.     }
  932. }
  933.  
  934. /*+-------------------------------------------------------------------------
  935.     wctx(flen)
  936. --------------------------------------------------------------------------*/
  937. wctx(flen)
  938. long flen;
  939. {
  940. register int thisblklen;
  941. register int firstch;
  942. register int sectnum;
  943. register int attempts;
  944. long charssent;
  945.  
  946.     charssent = 0;
  947.     firstsec=TRUE;
  948.     thisblklen = blklen;
  949.     report_txblklen(blklen);
  950.  
  951.     attempts = 8;
  952.     while(((firstch = readock(Rxtimeout,2)) != NAK) &&
  953.         (firstch  !=  WANTCRC) && (firstch  !=  WANTG) &&
  954.         (firstch != TIMEOUT) && (firstch != CAN))
  955.     {
  956.         if(!--attempts)
  957.         {
  958.             report_str("bad start stimulus",1);
  959.             send_cancel();
  960.             return(ERROR);
  961.         }
  962.     }
  963.  
  964.     if(firstch==CAN)
  965.     {
  966.         report_str("receiver CAN",1);
  967.         return(ERROR);
  968.     }
  969.  
  970.     if((firstch==WANTCRC) || (firstch==WANTG))
  971.         Crcflg=TRUE;
  972.  
  973.     report_protocol_crc_type((Crcflg)
  974.             ? ((firstch== WANTG) ? "/CRC-g" : "/CRC")
  975.             : "/CHK");
  976.  
  977.     sectnum=0;
  978.     for(;;)
  979.     {
  980.         if(flen <= (charssent + 896L))
  981.         {
  982.             thisblklen = 128;
  983.             report_txblklen(thisblklen);
  984.         }
  985.         if(!xbuf_build(txbuf,thisblklen))
  986.             break;
  987.         if(wcputsec(txbuf,++sectnum,thisblklen)==ERROR)
  988.             return(ERROR);
  989.         charssent += thisblklen;
  990.     }
  991.  
  992.     /* file transfer completed */
  993.     report_file_byte_io(this_file_length);
  994.     report_file_close();
  995.     fclose(in);
  996.  
  997.     attempts=0;
  998.     do
  999.     {
  1000.         purgeline();
  1001.         sendline(EOT);
  1002.         flushline();
  1003.         report_last_txhdr("EOT",0);
  1004.         ++attempts;
  1005.     }    while((firstch=(readock(Rxtimeout,1)) != ACK) && attempts < RETRYMAX);
  1006.     if(attempts == RETRYMAX)
  1007.     {
  1008.         report_str("No ACK on EOT",1);
  1009.         return(ERROR);
  1010.     }
  1011.     else
  1012.         return(OK);
  1013. }
  1014.  
  1015. wcputsec(buf,sectnum,cseclen)
  1016. unsigned char *buf;
  1017. int sectnum;
  1018. int cseclen;    /* data length of this block to send */
  1019. {
  1020.     register int checksum;
  1021.     register int wcj;
  1022.     register unsigned char *cp;
  1023.     unsigned short oldcrc;
  1024.     int firstch;
  1025.     int attempts;
  1026.  
  1027.     firstch=0;    /* part of logic to detect CAN CAN */
  1028.  
  1029.     sprintf(s128,"Sending block %d",sectnum);
  1030.     report_last_txhdr(s128,0);
  1031.     if(log_packets)
  1032.     {
  1033.         log_packet_buffer(buf,cseclen);
  1034.     }
  1035.  
  1036.     for(attempts=0; attempts <= RETRYMAX; attempts++)
  1037.     {
  1038.         Lastrx= firstch;
  1039.         sendline(cseclen == 1024 ? STX : SOH);
  1040.         sendline(sectnum);
  1041.         sendline(-sectnum - 1);
  1042.         oldcrc=checksum=0;
  1043.  
  1044.         for(wcj = cseclen,cp = buf; --wcj >= 0; )
  1045.         {
  1046.             sendline(*cp);
  1047.             oldcrc=updcrc(*cp,oldcrc);
  1048.             checksum += *cp++;
  1049.         }
  1050.         if(Crcflg)
  1051.         {
  1052.             oldcrc=updcrc(0,updcrc(0,oldcrc));
  1053.             sendline((int)(oldcrc >> 8));
  1054.             sendline((int)(oldcrc & 0xFF));
  1055.         }
  1056.         else
  1057.             sendline(checksum);
  1058.         flushline();
  1059.  
  1060.         if(Optiong)
  1061.         {
  1062.             firstsec = FALSE;
  1063.             return(OK);
  1064.         }
  1065.         firstch = readock(Rxtimeout,(Noeofseen&§num) ? 2:1);
  1066. gotnak:
  1067.         switch(firstch)
  1068.         {
  1069.         case CAN:
  1070.             if(Lastrx == CAN)
  1071.             {
  1072. cancan:
  1073.                 report_last_rxhdr("CAN",1);
  1074.                 return(ERROR);
  1075.             }
  1076.             break;
  1077.         case TIMEOUT:
  1078.             report_last_rxhdr("Timeout",1);
  1079.             continue;
  1080.         case WANTCRC:
  1081.             if(firstsec)
  1082.                 Crcflg = TRUE;
  1083.         case NAK:
  1084.             report_last_rxhdr("NAK",1);
  1085.             continue;
  1086.         case ACK:
  1087.             report_last_rxhdr("ACK",0);
  1088.             firstsec=FALSE;
  1089.             Totsecs += (cseclen>>7);
  1090.             return(OK);
  1091.         case ERROR:
  1092.             report_last_rxhdr("Noise",0);
  1093.             break;
  1094.         default:
  1095.             sprintf(s128,"0x%02x ???",firstch);
  1096.             report_last_rxhdr(s128,1);
  1097.             break;
  1098.         }
  1099.         for(;;)
  1100.         {
  1101.             Lastrx = firstch;
  1102.             if((firstch = readock(Rxtimeout,2)) == TIMEOUT)
  1103.                 break;
  1104.             if(firstch == NAK || firstch == WANTCRC)
  1105.                 goto gotnak;
  1106.             if(firstch == CAN && Lastrx == CAN)
  1107.                 goto cancan;
  1108.         }
  1109.     }
  1110.     report_str("retry count exceeded",1);
  1111.     return(ERROR);
  1112. }
  1113.  
  1114. /* fill buf with count chars padding with ^Z for CPM */
  1115. xbuf_build(buf,count)
  1116. register char *buf;
  1117. {
  1118. register c,m;
  1119. long lseek();
  1120. long X_txpos = lseek(fileno(in),0L,1);
  1121. char diag_str[64];
  1122.  
  1123.     report_send_stats(X_txpos);
  1124.     if( !Ascii)
  1125.     {
  1126.         m = read(fileno(in),buf,count);
  1127.         if(log_packets)
  1128.         {
  1129.             sprintf(diag_str,"read rtnd %d of %d",m,count);
  1130.             report_str(diag_str,1);
  1131.         }
  1132.         if(m <= 0)
  1133.             return(0);
  1134.         while(m < count)
  1135.             buf[m++] = 032;
  1136.         return(count);
  1137.     }
  1138.     m=count;
  1139.     if(Lfseen)
  1140.     {
  1141.         *buf++ = 012;
  1142.         --m;
  1143.         Lfseen = 0;
  1144.     }
  1145.     while((c=getc(in))!=EOF)
  1146.     {
  1147.         if(c == 012)
  1148.         {
  1149.             *buf++ = 015;
  1150.             if(--m == 0)
  1151.             {
  1152.                 Lfseen = TRUE;
  1153.                 break;
  1154.             }
  1155.         }
  1156.         *buf++ =c;
  1157.         if(--m == 0)
  1158.             break;
  1159.     }
  1160.     if(m==count)
  1161.         return(0);
  1162.     else
  1163.         while(--m>=0)
  1164.             *buf++ = CPMEOF;
  1165.     return(count);
  1166. }
  1167.  
  1168. /*+-------------------------------------------------------------------------
  1169.     zbuf_build(buf,count) - fill buf with count chars 
  1170. --------------------------------------------------------------------------*/
  1171. zbuf_build(buf,count)
  1172. register char *buf;
  1173. int count;
  1174. {
  1175. register c,m;
  1176.  
  1177.     m=count;
  1178.     while((c=getc(in))!=EOF)
  1179.     {
  1180.         *buf++ =c;
  1181.         if(--m == 0)
  1182.             break;
  1183.     }
  1184.     return(count - m);
  1185. }    /* end of zbuf_build */
  1186.  
  1187. /*+-------------------------------------------------------------------------
  1188.     SIGALRM_handler()
  1189. --------------------------------------------------------------------------*/
  1190. SIGALRM_handler()
  1191. {
  1192. #if defined(M_SYS5)
  1193.     report_rx_ind(0);
  1194.     report_tx_ind(0);
  1195. #endif
  1196.     longjmp(tohere,-1);
  1197. }    /* end of SIGALRM_handler */
  1198.  
  1199. /*+-------------------------------------------------------------------------
  1200.     readock(timeout,count)
  1201. timeout is in tenths of seconds reads character(s) from file
  1202. descriptor 'fd' read 'count' characters, (1 <= count <= 3) if more than
  1203. one received, return ERROR unless all are CAN normal response is NAK,
  1204. ACK, CAN, G or C
  1205. --------------------------------------------------------------------------*/
  1206. readock(timeout,count)
  1207. int timeout;
  1208. int count;
  1209. {
  1210.     register int c;
  1211.     static char byt[5];
  1212.  
  1213.     if(setjmp(tohere))
  1214.     {
  1215.         report_str("TIMEOUT",1);
  1216.         return(TIMEOUT);
  1217.     }
  1218.     c = timeout/10;
  1219.     if(c<2)
  1220.         c = 2;
  1221.     signal(SIGALRM,SIGALRM_handler);
  1222.     alarm(c);
  1223. #if defined(ONEREAD)
  1224.     c=read(iofd,byt,1);        /* regulus raw read is unique */
  1225. #else
  1226.     c=read(iofd,byt,count);
  1227. #endif
  1228.     rx_char_count += c;
  1229.     alarm(0);
  1230.     if(c<1)
  1231.         return(TIMEOUT);
  1232.     if(c==1)
  1233.         return(byt[0]&0377);
  1234.     else
  1235.         while(c)
  1236.             if(byt[--c] != CAN)
  1237.                 return(ERROR);
  1238.     return(CAN);
  1239. }    /* end of readock */
  1240.  
  1241.  
  1242. /*+-------------------------------------------------------------------------
  1243.     readline(n)
  1244. --------------------------------------------------------------------------*/
  1245. readline(n)
  1246. int n;
  1247. {
  1248.     return(readock(n,1));
  1249. }    /* end of readline */
  1250.  
  1251.  
  1252.  
  1253. /*+-------------------------------------------------------------------------
  1254.     purgeline()
  1255. --------------------------------------------------------------------------*/
  1256. purgeline()
  1257. {
  1258. #if defined(M_SYS5)
  1259.     ioctl(iofd,TCFLSH,0);
  1260. #else
  1261.     lseek(iofd,0L,2);
  1262. #endif
  1263. }    /* end of purgeline */
  1264.  
  1265.  
  1266. /*+-------------------------------------------------------------------------
  1267.     send_cancel() - send cancel to remote
  1268. --------------------------------------------------------------------------*/
  1269. send_cancel()
  1270. {
  1271.     static char canistr[] =
  1272.     {
  1273.         24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  1274.     };
  1275.     register char *cptr = canistr;
  1276.  
  1277.     report_last_txhdr("^X CAN",1);
  1278.     while(*cptr)
  1279.         sendline(*cptr++);
  1280.     flushline();
  1281. }    /* end of send_cancel */
  1282.  
  1283.  
  1284. /*+-------------------------------------------------------------------------
  1285.     substr(str,substr) - searches for substr in string str
  1286. --------------------------------------------------------------------------*/
  1287. char *
  1288. substr(str,substr)
  1289. register char *str,*substr;
  1290. {
  1291. register char *sptr;
  1292. register char *ssptr;
  1293.  
  1294.     for(sptr = str; *str; str++)
  1295.     {
  1296.         if(*str == *substr)
  1297.         {
  1298.             sptr = str;
  1299.             ssptr = substr;
  1300.             while(1)
  1301.             {
  1302.                 if(*ssptr == 0)
  1303.                     return(str);
  1304.                 if(*sptr++ != *ssptr++)
  1305.                     break;
  1306.             }
  1307.         }
  1308.     }
  1309.     return(NULL);
  1310. }    /* end of substr */
  1311.  
  1312. /*+-------------------------------------------------------------------------
  1313.     usage()
  1314. --------------------------------------------------------------------------*/
  1315. usage()
  1316. {
  1317.     exit(255);
  1318. }    /* end of usage */
  1319.  
  1320. /*+-------------------------------------------------------------------------
  1321.     getzrxinit() - Get the receiver's init parameters
  1322. --------------------------------------------------------------------------*/
  1323. getzrxinit()
  1324. {
  1325.     register n;
  1326.     struct stat f;
  1327.  
  1328.     for(n=10; --n>=0; )
  1329.     {
  1330.         switch(zgethdr(Rxhdr,1))
  1331.         {
  1332.         case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  1333.             stohdr(Rxpos);
  1334.             zshhdr(ZACK,Txhdr);
  1335.             continue;
  1336.         case ZCOMMAND:        /* They didn't see out ZRQINIT */
  1337.             stohdr(0L);
  1338.             zshhdr(ZRQINIT,Txhdr);
  1339.             continue;
  1340.         case ZRINIT:
  1341.             Rxflags = 0377 & Rxhdr[ZF0];
  1342.             Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  1343.             report_protocol_type("ZMODEM");
  1344.             report_protocol_crc_type((Txfcs32) ? "/CRC32" : "/CRC16");
  1345.             Zctlesc |= Rxflags & TESCCTL;
  1346.             Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  1347.             if( !(Rxflags & CANFDX))
  1348.                 Txwindow = 0;
  1349. #if defined(MODE2OK)
  1350.             mode(2);    /* Set cbreak,XON/XOFF,etc. */
  1351. #endif
  1352. #if !defined(READCHECK)
  1353. #if !defined(M_SYS5)
  1354.             /* Use 1024 byte frames if no sample/interrupt */
  1355.             if(Rxbuflen < 32 || Rxbuflen > 1024)
  1356.             {
  1357.                 Rxbuflen = 1024;
  1358.             }
  1359. #endif
  1360. #endif
  1361.             /* Override to force shorter frame length */
  1362.             if(Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
  1363.                 Rxbuflen = Tframlen;
  1364.             if( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
  1365.                 Rxbuflen = Tframlen;
  1366.  
  1367.             /* If using a pipe for testing set lower buf len */
  1368.             fstat(iofd,&f);
  1369.             if((f.st_mode & S_IFMT) != S_IFCHR
  1370.                 && (Rxbuflen == 0 || Rxbuflen > 4096))
  1371.                 Rxbuflen = 4096;
  1372.             sprintf(s128,"Remote: CRC32 %c  duplex %c",
  1373.                 (Rxflags & CANFC32) ? 'y' : 'n',
  1374.                 (Rxflags & CANFDX)  ? 'y' : 'n');
  1375.             if(Rxbuflen)
  1376.                 sprintf(&s128[strlen(s128)],"  buflen %u",Rxbuflen);
  1377.             else
  1378.                 strcat(s128,"  continuous stream y");
  1379.             report_str(s128,2);
  1380.             /*
  1381.              * If input is not a regular file,force ACK's each 1024
  1382.              *  (A smarter strategey could be used here ...)
  1383.              */
  1384.             if( !Command)
  1385.             {
  1386.                 fstat(fileno(in),&f);
  1387.                 if(((f.st_mode & S_IFMT) != S_IFREG)
  1388.                     && (Rxbuflen == 0 || Rxbuflen > 1024))
  1389.                     Rxbuflen = 1024;
  1390.             }
  1391.  
  1392.             if(Baudrate > 300)    /* Set initial subpacket len */
  1393.                 blklen = 256;
  1394.             if(Baudrate > 1200)
  1395.                 blklen = 512;
  1396.             if(Baudrate >= 2400)    /* original code had > 2400 here ****/
  1397.                 blklen = 1024;
  1398.             if(Rxbuflen && blklen>Rxbuflen)
  1399.                 blklen = Rxbuflen;
  1400.             if(blkopt && blklen > blkopt)
  1401.                 blklen = blkopt;
  1402.             blklen_original = blklen;
  1403.             report_txblklen(blklen);
  1404.             return(sendzsinit());
  1405.         case ZCAN:
  1406.         case TIMEOUT:
  1407.             return(ERROR);
  1408.         case ZRQINIT:
  1409.             if(Rxhdr[ZF0] == ZCOMMAND)
  1410.                 continue;
  1411.         default:
  1412.             zshhdr(ZNAK,Txhdr);
  1413.             continue;
  1414.         }
  1415.     }
  1416.     return(ERROR);
  1417. }    /* end of getzrxinit */
  1418.  
  1419.  
  1420. /*+-------------------------------------------------------------------------
  1421.     sendzsinit() - send send-init information
  1422. --------------------------------------------------------------------------*/
  1423. sendzsinit()
  1424. {
  1425.     register c;
  1426.  
  1427.     if(Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
  1428.         return(OK);
  1429.     errors = 0;
  1430.     for(;;)
  1431.     {
  1432.         stohdr(0L);
  1433.         if(Zctlesc)
  1434.         {
  1435.             Txhdr[ZF0] |= TESCCTL;
  1436.             zshhdr(ZSINIT,Txhdr);
  1437.         }
  1438.         else
  1439.             zsbhdr(ZSINIT,Txhdr);
  1440.         zsdata(Myattn,1+strlen(Myattn),ZCRCW);
  1441.         c = zgethdr(Rxhdr,1);
  1442.         switch(c)
  1443.         {
  1444.         case ZCAN:
  1445.             return(ERROR);
  1446.         case ZACK:
  1447.             return(OK);
  1448.         default:
  1449.             if(++errors > 19)
  1450.                 return(ERROR);
  1451.             continue;
  1452.         }
  1453.     }
  1454. }    /* end of sendzsinit */
  1455.  
  1456. /*+-------------------------------------------------------------------------
  1457.     zsendfile(buf,blen) - send file name & info
  1458. --------------------------------------------------------------------------*/
  1459. zsendfile(buf,blen)
  1460. char *buf;
  1461. int blen;
  1462. {
  1463.     register c;
  1464.  
  1465.     for(;;)
  1466.     {
  1467.         blklen = blklen_original;
  1468.         report_txblklen(blklen);
  1469.         Txhdr[ZF0] = Lzconv;    /* file conversion request */
  1470.         Txhdr[ZF1] = Lzmanag;    /* file management request */
  1471.         Txhdr[ZF2] = Lztrans;    /* file transport request */
  1472.         Txhdr[ZF3] = 0;
  1473.         zsbhdr(ZFILE,Txhdr);
  1474.         zsdata(buf,blen,ZCRCW);
  1475. again:
  1476.         c = zgethdr(Rxhdr,1);
  1477.         switch(c)
  1478.         {
  1479.         case ZRINIT:
  1480.             while((c = readline(50)) > 0)
  1481.                 if(c == ZPAD)
  1482.                 {
  1483.                     goto again;
  1484.                 }
  1485.             /* **** FALL THRU TO **** */
  1486.         default:
  1487.             continue;
  1488.         case ZCAN:
  1489.         case TIMEOUT:
  1490.         case ZABORT:
  1491.         case ZFIN:
  1492.             return(ERROR);
  1493.         case ZSKIP:
  1494.             report_file_close();
  1495.             fclose(in);
  1496.             return(c);
  1497.         case ZRPOS:
  1498.             /*
  1499.              * Suppress zcrcw request otherwise triggered by
  1500.              * lastsync==bytcnt
  1501.              */
  1502.             Lastsync = (bytcnt = Txpos = Rxpos) -1;
  1503.             fseek(in,Rxpos,0);
  1504.             Dontread = FALSE;
  1505.             report_send_stats(Txpos);
  1506.             return(zsendfdata());
  1507.         }
  1508.     }
  1509. }    /* end of zsendfile */
  1510.  
  1511. /*+-------------------------------------------------------------------------
  1512.     zsendfdata() - send data in the file
  1513. --------------------------------------------------------------------------*/
  1514. zsendfdata()
  1515. {
  1516. register c,e,n;
  1517. register newcnt;
  1518. register long tcount = 0;
  1519. int junkcount;        /* Counts garbage chars received by TX */
  1520. static int tleft = 6;    /* Counter for test mode */
  1521. int err;
  1522.  
  1523.     Lrxpos = 0;
  1524.     junkcount = 0;
  1525.     SameZrposAgain = FALSE;        /* variable was named Beenhereb4 (wht) */
  1526.     this_file_frame_count = 0;    /* we've sent no frames (wht) */
  1527. somemore:
  1528.     if(setjmp(intrjmp))
  1529.     {
  1530. waitack:
  1531.         junkcount = 0;
  1532.         c = getinsync(0);
  1533. gotack:
  1534.         switch(c)
  1535.         {
  1536.         default:
  1537.         case ZCAN:
  1538.             report_rcvr_cancelled("zfdata-1");
  1539.             report_file_close();
  1540.             fclose(in);
  1541.             return(ERROR);
  1542.         case ZSKIP:
  1543.             report_file_close();
  1544.             fclose(in);
  1545.             return(c);
  1546.         case ZACK:
  1547.         case ZRPOS:
  1548.             break;
  1549.         case ZRINIT:
  1550.             return(OK);
  1551.         }
  1552. #if defined(READCHECK)
  1553.         /*
  1554.          * If the reverse channel can be tested for data,
  1555.          *  this logic may be used to detect error packets
  1556.          *  sent by the receiver,in place of setjmp/longjmp
  1557.          *  rdchk(fdes) returns non 0 if a character is available
  1558.          */
  1559.         while(rdchk(iofd))
  1560.         {
  1561.             switch(readline(1))
  1562.             {
  1563.             case CAN:
  1564.             case ZPAD:
  1565.                 c = getinsync(1);
  1566.                 goto gotack;
  1567.             case XOFF:        /* Wait a while for an XON */
  1568.             case XOFF|0200:
  1569.                 readline(100);
  1570.             }
  1571.         }
  1572. #endif
  1573.     }
  1574.  
  1575.     newcnt = Rxbuflen;
  1576.     Txwcnt = 0;
  1577.     stohdr(Txpos);
  1578.     zsbhdr(ZDATA,Txhdr);
  1579.  
  1580.     do
  1581.     {
  1582.         if(Dontread)
  1583.         {
  1584.             n = Lastn;
  1585.         } else
  1586.         {
  1587.             n = zbuf_build(txbuf,blklen);
  1588.             Lastread = Txpos;
  1589.             Lastn = n;
  1590.         }
  1591.         Dontread = FALSE;
  1592.         if(n < blklen)
  1593.             e = ZCRCE;
  1594.         else if(junkcount > 3)
  1595.             e = ZCRCW;
  1596.         else if(bytcnt == Lastsync)
  1597.             e = ZCRCW;
  1598.         else if(Rxbuflen && (newcnt -= n) <= 0)
  1599.             e = ZCRCW;
  1600.         else if(Txwindow && (Txwcnt += n) >= Txwspac)
  1601.         {
  1602.             Txwcnt = 0;
  1603.             e = ZCRCQ;
  1604.         }
  1605.         else
  1606.             e = ZCRCG;
  1607.         zsdata(txbuf,n,e);
  1608.         this_file_frame_count++;        /* wht */
  1609.         if(bad_condx_blklen)            /* wht */
  1610.         {
  1611.             /* if we have sent four frames since last ZRPOS to same pos (wht)*/
  1612.             if((this_file_frame_count - bad_condx_frame_count) > 4) /*wht*/
  1613.             {
  1614.                 if(blklen == bad_condx_blklen)
  1615.                     bad_condx_blklen = 0;
  1616.                 else
  1617.                 {
  1618.                     blklen *= 2;
  1619.                     report_txblklen(blklen);
  1620.                 }
  1621.                 SameZrposAgain = 0;
  1622.             }
  1623.         }
  1624.         bytcnt = Txpos += n;
  1625.         report_send_stats(Txpos);
  1626.         if(e == ZCRCW)
  1627.             goto waitack;
  1628. #if defined(READCHECK)
  1629.         /*
  1630.          * If the reverse channel can be tested for data,
  1631.          *  this logic may be used to detect error packets
  1632.          *  sent by the receiver,in place of setjmp/longjmp
  1633.          *  rdchk(fdes) returns non 0 if a character is available
  1634.          */
  1635.         while(rdchk(iofd))
  1636.         {
  1637.             switch(readline(1))
  1638.             {
  1639.             case CAN:
  1640.             case ZPAD:
  1641.                 c = getinsync(1);
  1642.                 if(c == ZACK)
  1643.                     break;
  1644. #if defined(TCFLSH)
  1645.                 ioctl(iofd,TCFLSH,1);
  1646. #endif
  1647.                 /* zcrce - dinna wanna starta ping-pong game */
  1648.                 zsdata(txbuf,0,ZCRCE);
  1649.                 goto gotack;
  1650.  
  1651.             case XOFF:        /* Wait a while for an XON */
  1652.             case XOFF|0200:
  1653.                 readline(100);
  1654.  
  1655.             default:
  1656.                 ++junkcount;
  1657.             }
  1658.         }
  1659. #endif    /* READCHECK */
  1660.         if(Txwindow)
  1661.         {
  1662.             while((tcount = Txpos - Lrxpos) >= Txwindow)
  1663.             {
  1664.                 if(e != ZCRCQ)
  1665.                     zsdata(txbuf,0,e = ZCRCQ);
  1666.                 c = getinsync(1);
  1667.                 if(c != ZACK)
  1668.                 {
  1669. #if defined(TCFLSH)
  1670.                     ioctl(iofd,TCFLSH,1);
  1671. #endif
  1672.                     zsdata(txbuf,0,ZCRCE);
  1673.                     goto gotack;
  1674.                 }
  1675.             }
  1676.         }
  1677.     } while(n == blklen);
  1678.  
  1679.     for(;;)
  1680.     {
  1681.         stohdr(Txpos);
  1682.         zsbhdr(ZEOF,Txhdr);
  1683.         switch(err = getinsync(0))
  1684.         {
  1685.         case ZACK:
  1686.             continue;
  1687.         case ZRPOS:
  1688.             goto somemore;
  1689.         case ZRINIT:
  1690.             return(OK);
  1691.         case ZSKIP:
  1692.             report_file_close();
  1693.             fclose(in);
  1694.             return(c);
  1695.         default:
  1696.             sprintf(s128,"SEND protocol sync error 0x%04x: %s",err,Pathname);
  1697.             report_str(s128 + 5,1);
  1698.             skip_count++;
  1699.             report_error_count();
  1700.             report_file_byte_io(this_file_length);
  1701.             report_file_close();
  1702.             fclose(in);
  1703.             return(ERROR);
  1704.         }
  1705.     }
  1706. }    /* end of zsendfdata */
  1707.  
  1708. /*+-------------------------------------------------------------------------
  1709.     getinsync(flag) - get back in sync with receiver
  1710. --------------------------------------------------------------------------*/
  1711. getinsync(flag)
  1712. {
  1713.     register c;
  1714.  
  1715.     for(;;)
  1716.     {
  1717.         switch(c = zgethdr(Rxhdr,0))
  1718.         {
  1719.         case ZCAN:
  1720.         case ZABORT:
  1721.         case ZFIN:
  1722.         case TIMEOUT:
  1723.             sprintf(s128,"Receiver %s",frametypes[c+FTOFFSET]);
  1724.             report_str(s128,1);
  1725.             return(ERROR);
  1726.         case ZRPOS:
  1727.             report_str("Receiver ZRPOS",1);
  1728.             /* ************************************* */
  1729.             /*  If sending to a modem buffer,you    */
  1730.             /*   might send a break at this point to */
  1731.             /*   dump the modem's buffer.            */
  1732.             /* ************************************* */
  1733.             if(Lastn >= 0 && Lastread == Rxpos)
  1734.             {
  1735.                 Dontread = TRUE;
  1736.             } else
  1737.             {
  1738.                 clearerr(in);    /* In case file EOF seen */
  1739.                 fseek(in,Rxpos,0);
  1740.             }
  1741.             bytcnt = Lrxpos = Txpos = Rxpos;
  1742.             if(Lastsync == Rxpos)                    /* wht - original code */
  1743.             {                                        /* wht - original code */
  1744.                 /* save frame count at time of each occurrence (wht) */
  1745.                 bad_condx_frame_count = this_file_frame_count;    /* wht */
  1746.                 /* save block length at time of error (wht) */
  1747.                 if(++SameZrposAgain > 4)            /* wht - original code */
  1748.                 {                                    /* wht */
  1749.                     if(bad_condx_blklen == 0)        /* wht */
  1750.                         bad_condx_blklen = blklen;    /* wht */
  1751.                     if(blklen > 256)                /* wht - 32->256 */
  1752.                     {
  1753.                         blklen /= 2;                /* wht - original code */
  1754.                         report_txblklen(blklen);
  1755.                     }
  1756.                 }                                    /* wht */
  1757.             }                                        /* wht - original code */
  1758.             Lastsync = Rxpos;
  1759.             report_send_stats(Txpos);
  1760.             return(c);
  1761.         case ZACK:
  1762.             report_str("",-1);
  1763.             Lrxpos = Rxpos;
  1764.             if(flag || Txpos == Rxpos)
  1765.                 return(ZACK);
  1766.             continue;
  1767.  
  1768.         case ZRINIT:
  1769.         case ZSKIP:
  1770.             report_str("",-1);
  1771.             report_file_byte_io(this_file_length);
  1772.             report_file_close();
  1773.             fclose(in);
  1774.             return(c);
  1775.         case ERROR:
  1776.         default:
  1777.             report_str("Sending ZNAK",1);
  1778.             zsbhdr(ZNAK,Txhdr);
  1779.             continue;
  1780.         }
  1781.     }
  1782. }    /* end of getinsync */
  1783.  
  1784. /*+-------------------------------------------------------------------------
  1785.     saybibi() - Say "bibi" to the receiver, try to do it cleanly
  1786. --------------------------------------------------------------------------*/
  1787. saybibi()
  1788. {
  1789.     for(;;)
  1790.     {
  1791.         stohdr(0L);        /* CAF Was zsbhdr - minor change */
  1792.         zshhdr(ZFIN,Txhdr);    /*  to make debugging easier */
  1793.         switch(zgethdr(Rxhdr,0))
  1794.         {
  1795.         case ZFIN:
  1796.             sendline('O');
  1797.             sendline('O');
  1798.             flushline();
  1799.         case ZCAN:
  1800.         case TIMEOUT:
  1801.             return;
  1802.         }
  1803.     }
  1804. }    /* end of saybibi */
  1805.  
  1806. /*+-------------------------------------------------------------------------
  1807.     determine_transaction_time()
  1808. --------------------------------------------------------------------------*/
  1809. determine_transaction_time()
  1810. {
  1811. register c;
  1812. struct stat f;
  1813. char *name;
  1814.  
  1815.     rewind_file_list();
  1816.     TotalLeft = 0;
  1817.     Filesleft = 0;
  1818.     while(get_file_list_name(&name))
  1819.     {
  1820.         f.st_size = -1;
  1821.         if((access(name,04) >= 0) && (stat(name,&f) >= 0))
  1822.         {
  1823.             c = f.st_mode & S_IFMT;
  1824.             if(c != S_IFDIR && c != S_IFBLK)
  1825.             {
  1826.                 ++Filesleft;
  1827.                 TotalLeft += f.st_size;
  1828.             }
  1829.         }
  1830.     }
  1831.     FilesTotal = Filesleft;
  1832.     rewind_file_list();
  1833. }    /* end of determine_transaction_time */
  1834.  
  1835. /* vi: set tabstop=4 shiftwidth=4: */
  1836. /* end of tipsz.c */
  1837.